package zhxt.helmet.utils;
import org.bytedeco.javacpp.DoublePointer;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.global.opencv_imgcodecs;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.Mat;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.bytedeco.javacpp.BytePointer;

import static org.bytedeco.opencv.global.opencv_imgproc.*;

public class FrameToMatConverter {
    /**
     * 将 Frame 转换为 Mat (默认输出BGR格式)
     * @param frame 输入的Frame对象
     * @return 转换后的Mat对象 (需要调用者手动释放)
     * @throws IllegalArgumentException 如果输入帧无效
     */
    public static Mat frameToMat(Frame frame) {
        if (frame == null || frame.image == null || frame.image.length == 0) {
            throw new IllegalArgumentException("输入帧无效");
        }

        int width = frame.imageWidth;
        int height = frame.imageHeight;
        int channels = frame.imageChannels;
        int depth = frame.imageDepth;

        // 只支持8位无符号整型
        if (depth != Frame.DEPTH_UBYTE) {
            throw new IllegalArgumentException("只支持8位无符号整型数据");
        }
        //保存Frame为图片验证数据有效
        //saveFrameToFile(frame,"output.jpg");

        // 获取ByteBuffer并确保有数据
        ByteBuffer buffer = (ByteBuffer) frame.image[0];
        if (buffer == null || !buffer.hasArray()) {
            throw new IllegalArgumentException("Frame数据不可访问");
        }

        // 创建BytePointer的正确方式
        BytePointer bp = new BytePointer(buffer.array());

        // 创建Mat对象 (与Frame共享数据)
        Mat mat = new Mat(height, width,
                opencv_core.CV_8UC(channels),
                bp);

        // 根据通道数处理颜色空间
        Mat result = new Mat();
        try {
            switch (channels) {
                case 1: // 灰度 -> BGR
                    cvtColor(mat, result, COLOR_GRAY2BGR);
                    break;
                case 3: // 假设Frame是RGB格式 -> 转BGR
                    cvtColor(mat, result, COLOR_RGB2BGR);
                    break;
                case 4: // RGBA -> BGR (丢弃alpha通道)
                    cvtColor(mat, result, COLOR_RGBA2BGR);
                    break;
                default:
                    throw new IllegalArgumentException("不支持的通道数: " + channels);
            }
            return result;
        } finally {
            mat.close();
        }
    }



    // 检查数据是否连续（无行填充）
    private static boolean isContinuous(int width, int channels, int totalBytes, int height) {
        int expectedBytes = width * height * channels;
        return totalBytes == expectedBytes;
    }
    //将org.opencv.core.Mat保存为图片, 用于验证转换是否成功
    /**
     * 将 org.bytedeco.opencv 的 Mat 对象保存为图片文件
     * @param mat 要保存的 Mat 对象
     * @param outputPath 输出文件路径（包含扩展名，如 ".jpg", ".png"）
     * @throws IllegalArgumentException 如果 Mat 为空或保存失败
     */
    public static void saveMatToFile(Mat mat, String outputPath) {
        if (mat == null || mat.empty()) {
            throw new IllegalArgumentException("输入的 Mat 对象为空或无效");
        }

        if (outputPath == null || outputPath.trim().isEmpty()) {
            throw new IllegalArgumentException("输出路径不能为空");
        }

        // 检查 Mat 类型并转换为适合保存的类型（如果需要）
        Mat saveMat = prepareMatForSaving(mat);

        try {
            // 使用 opencv_imgcodecs.imwrite 保存图片
            boolean success = opencv_imgcodecs.imwrite(outputPath, saveMat);

            if (!success) {
                throw new RuntimeException("无法保存图片到: " + outputPath +
                        " - 可能是路径无效、权限问题或不受支持的格式");
            }
        } finally {
            // 如果创建了临时 Mat，确保释放它
            if (saveMat != mat) {
                saveMat.close();
            }
        }
    }

    /**
     * 准备 Mat 对象以便保存（如果是浮点型 转换为 8UC。）
     */
    private static Mat prepareMatForSaving(Mat mat) {
        // 如果已经是 8UC1、8UC3 或 8UC4 类型，直接返回
        if (mat.type() == opencv_core.CV_8UC1 ||
                mat.type() == opencv_core.CV_8UC3 ||
                mat.type() == opencv_core.CV_8UC4) {
            return mat;
        }

        // 对于浮点型 Mat（如 CV_32F），需要转换为 8UC
        Mat converted = new Mat();
        DoublePointer minVal = null;
        DoublePointer maxVal = null;
        try {
            minVal = new DoublePointer(1);
            maxVal = new DoublePointer(1);

            // 正确的 minMaxLoc 调用方式
            opencv_core.minMaxLoc(mat, minVal, maxVal, null, null, new Mat());

            double min = minVal.get();
            double max = maxVal.get();

            if (mat.channels() == 1) {
                // 单通道
                mat.convertTo(converted, opencv_core.CV_8UC1, 255.0 / (max - min), -min * 255.0 / (max - min));
            } else {
                // 多通道
                mat.convertTo(converted, opencv_core.CV_8UC3, 255.0 / (max - min), -min * 255.0 / (max - min));
            }

            return converted;
        } catch (Exception e) {
            converted.close();
            throw new RuntimeException("无法转换 Mat 类型以便保存", e);
        } finally {
            // 释放 DoublePointer 资源
            if (minVal != null) {
                minVal.close();
            }
            if (maxVal != null) {
                maxVal.close();
            }
        }
    }

    //保存frame为文件, 用于验证是否成功接收到frame
    private static void saveFrameToFile(Frame frame, String outputPath) {
        Java2DFrameConverter converter = new Java2DFrameConverter();
        BufferedImage image = converter.getBufferedImage(frame);
        try {
            ImageIO.write(image, "jpg", new File(outputPath));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}